Introduction
Using This
Dataset
The purpose of using this data set is to build models that predict
student academic success. However, a significant challenge associated
with this endeavor is the strong class imbalance in the data, as
described by the authors in “Early Prediction of student’s Performance
in Higher Education: A Case Study.” The goal of this report is to use
exploratory data analysis to examine the features closely correlated
with student academic performance, as measured by first- and
second-semester grade average. Understanding these relationships may
help inform the development of machine learning models that more
accurately predict academic success while mitigating bias.
Description of
Data
This dataset contains features provided by a higher education
institution in Portugal and collected from various disjoint databases
about students at the time of their enrollment in an undergraduate
degree program. The purpose of the dataset is to predict student dropout
and academic success. The features relate to student demographics,
socio-economic indicators, degree program, and academic performance at
the end of the first and second semesters. The collected data previously
underwent cleaning.
List of Features
The dataset contains 4,424 observations and 34 feature variables.
- Marital Status (categorical): 6 categories include
single, married, widower, divorced, de facto union, or legally
separated; 88.6% of students are categorized as single.
- Application mode (categorical): 18 categories
include information related to the student’s application classifiers,
such as international student, special contingent, special age category,
and transfer student.
- Application order (categorical): 8 categories of
preferred application order between first choice and last choice.
- Course (categorical): 17 categories for chosen
course of study.
- Daytime/evening attendance (binary): Whether a
student attends during the day or in the evening; 89.08% attend during
the day.
- Previous Qualification (categorical): 17 categories
of highest education level, from secondary education to master’s degree;
84.02% of students completed their secondary education (12th year of
schooling or equivalent).
- Nationality (categorical): 21 nationalities
represented, 97.5% Portuguese and the remaining international
students.
- Mother’s Qualification and Father’s
Qualification (categorical): 29 and 34 categories of highest
education level, respectively.
- Mother’s Occupation and Father’s
Occupation (categorical): 32 and 46 categories of occupation,
respectively.
- Displaced (binary): Whether or not a student is
displaced; 54.84% of students are displaced.
- Educational special needs (binary): 1.15% of
students reported educational special needs.
- Debtor (binary): Whether or not a student has debt;
11.37% of students have debt.
- Tuition fees up to date (binary): Whether or not a
student’s tuition fees are up to date; 11.93% are not up-to-date on
their payments.
- Gender (binary): 64.83% of students are female
- Scholarship holder (binary): 24.84% of students
hold a scholarship.
- Age at enrollment (integer): Age of the student
when they are enrolled; 64.94% are 21 years old or younger.
- International student (binary): International
students (i.e., not from Portugal) account for 2.49% of the sample.
- Curricular Units 1st Semester and
Curricular Units 2nd Semester (integers): Number of
curricular units Credited, Enrolled,
and Approved for each semester.
Evaluations encompasses the number of evaluations to
curricular units in each semester, and Without
Evaluations is the number of curricular units without
evaluations in each semester. Grade is the average
grade between 0 and 20 per semester.
- Economic variables (continuous): This dataset includes continuous
variables related to the Unemployment Rate,
Inflation Rate, and GDP.
- Target (categorical): A student’s academic outcome:
Dropout, graduate, enrolled.
data <- read.csv("https://christinekillion.github.io/machine_learning/data/student-success.csv")
# Change column names
colnames(data) <- c(
"Marital", "Application_M", "Application_O", "Course",
"Attendance", "S_Qual", "Nationality",
"M_Qual", "F_Qual", "M_Occ",
"F_Occ", "Displaced", "Special_Needs", "Debtor",
"Tuition", "Gender", "Scholarship", "Age",
"International", "U_Credited1", "U_Enrolled1",
"U_Evaluated1", "U_Approved1",
"Grade1", "U_WO_Eval1",
"U_Credited2", "U_Enrolled2",
"U_Evaluated2", "U_Approved2",
"Grade2", "U_WO_Eval2",
"Unemployment", "Inflation", "GDP", "Target"
)
# Create random observation ID and replace 8% of the corresponding observations with missing values
grades1.missing.id <- sample(1:4424, 353, replace = FALSE)
grades2.missing.id <- sample(1:4424, 354, replace = FALSE)
data$Grade1[grades1.missing.id] <- NA
data$Grade2[grades2.missing.id] <- NA
#Total the number of missing values per column.
missing_per_column <- colSums(is.na(data))
#Total the number of missing values in the dataset.
total_missing <- sum(is.na(data))
Distribution of
Individual Features
This section will describe the univariate distributions of the key
categorical, dichotomous, and continuous features in the dataset and
analyze any potential issues for machine learning applications.
Student Groups of
Interest
There are three key groups that are underrepresented within this
dataset and should be carefully considered in the development of machine
learning models so as not to reproduce bias. Section 3 of this report
explores in more detail the relationship between these groups and
academic achievement in the dataset.
# Count the number of occurrences for each category
debtor_counts <- table(data$Debtor)
tuition_counts <- table(data$Tuition)
gender_counts <- table(data$Gender)
# Create data frames from the counts for each category
debtor_df <- as.data.frame(debtor_counts)
tuition_df <- as.data.frame(tuition_counts)
gender_df <- as.data.frame(gender_counts)
# Recode binary values from numbers to categories
debtor_df$Var1 <- recode(debtor_df$Var1, `1` = "Debt", `0` = "No Debt")
tuition_df$Var1 <- recode(tuition_df$Var1, `1` = "Paid", `0` = "Unpaid")
gender_df$Var1 <- recode(gender_df$Var1, `1` = "Male", `0` = "Female")
# Create the pie charts with ggplot2
# Debtor Pie Chart
pie_debtor <- ggplot(debtor_df, aes(x = "", y = Freq, fill = Var1)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") + # Convert bar chart to pie chart
scale_fill_manual(values = c("#4C57B8", "#AFB1F0")) +
theme_void() + # Remove background and axes
guides(fill = guide_legend(title = NULL)) + # Add legend and remove title
ggtitle("Debtor Status") # Remove individual title
# Tuition Fees Pie Chart
pie_tuition <- ggplot(tuition_df, aes(x = "", y = Freq, fill = Var1)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") + # Convert bar chart to pie chart
scale_fill_manual(values = c("#F5A1B5", "#ac1f67")) +
theme_void() + # Remove background and axes
guides(fill = guide_legend(title = NULL)) + # Add legend and remove title
ggtitle("Tuition Fees") # Remove individual title
# Gender Pie Chart
pie_gender <- ggplot(gender_df, aes(x = "", y = Freq, fill = Var1)) +
geom_bar(stat = "identity", width = 1) +
coord_polar(theta = "y") + # Convert bar chart to pie chart
scale_fill_manual(values = c("#E6DE3C", "#B9A520")) +
theme_void() + # Remove background and axes
guides(fill = guide_legend(title = NULL)) + # Add legend and remove title
ggtitle("Gender")
# Combine the pie charts into a grid with a centered main title
grid.arrange(
pie_debtor, pie_tuition, pie_gender,
ncol = 3,
heights = unit(c(1, 0.1), "npc") # Allocate space for the legends
)

Parental
Education
This dataset contains the previous academic qualifications of the
student, mother, and father. For students, 84.02% have completed
secondary education. The parental qualification distributions do not
reflect that of the students: There is a wider range of educational
categories for each of the parent groups (likely due to the disparate
sources of data). When recoded and grouped into three main categories
(secondary education, higher education, and other), the distribution of
parent qualifications in the dataset indicates that most of the parent
qualifications fall into the “other” category. More recoding is required
to classify qualifications in order to examine the relationship between
parent qualification and student grades.
# Create a dataframe with 4 rows and 34 columns. First column is Var1, 1:34
qual <- data.frame(matrix(1:34, nrow = 34, ncol = 1))
colnames(qual) <- c("Var1")
# Calculate the count of each category
S_qual <- data.frame(table(data$S_Qual))
M_qual <- data.frame(table(data$M_Qual))
F_qual <- data.frame(table(data$F_Qual))
# Merge by the common column "Var1"
qual <- merge(qual, S_qual, by = "Var1", all=TRUE)
qual <- merge(qual, M_qual, by = "Var1", all=TRUE)
qual <- merge(qual, F_qual, by = "Var1", all=TRUE)
colnames(qual) <- c("Qualification", "Student", "Mother", "Father")
# Replace NAs with 0
qual[is.na(qual)] <- 0
# Pivot the data to long format
qual_long <- qual %>%
pivot_longer(cols = c(Student, Mother, Father),
names_to = "Role",
values_to = "Count")
# Filter for only Mother and Father roles
qual_long <- qual_long %>%
filter(Role %in% c("Mother", "Father"))
# Group and rename the 'Qualification' categories
qual_long <- qual_long %>%
mutate(Qualification = case_when(
Qualification == 1 ~ "Secondary Education",
Qualification >= 2 & Qualification <= 6 ~ "Higher Education Degree",
Qualification >= 7 & Qualification <= 34 ~ "Other",
TRUE ~ as.character(Qualification) # In case there are any NA or unrecognized values
))
# Aggregate the data by Qualification and Role to get total count
qual_long_aggregated <- qual_long %>%
group_by(Qualification, Role) %>%
summarise(TotalCount = sum(Count), .groups = 'drop')
# Create the ggplot object for stacked bar plot
p <- ggplot(qual_long_aggregated, aes(x = Qualification, y = TotalCount, fill = Role, text = paste("Total Count: ", TotalCount))) +
geom_bar(stat = "identity") + # Use stat="identity" to use the actual counts
labs(x = "Qualification", y = "Count", fill = "Role") +
ggtitle("Distribution of Parent Qualifications (Grouped by Education Level)") + # Add title here
scale_fill_manual(values = c("Mother" = "#FFC20A", "Father" = "#0C7BDC")) + # Set custom colors
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# Convert the ggplot object to a plotly object for interactivity
interactive_plot <- ggplotly(p, tooltip = "text")
# Show the interactive plot
interactive_plot
Grade
Distribution
The grade features for each semester contain both missing values and
values of zero. When grades of zero are excluded, the grade
distributions are approximately normally distributed. Data imputation
could replace the missing values, or another binary feature can be
created to retain the information of students with a grade of zero for
each semester.
# Remove grades of zero
first_semester_grades <- data$Grade1[data$Grade1 != 0]
second_semester_grades <- data$Grade2[data$Grade2 != 0]
# Plot for first semester
gradeplot1 <- ggplot(data.frame(grade = first_semester_grades), aes(x = grade)) +
geom_histogram(aes(y = ..density..), bins = 10, fill = "#ac1f67", color = "black", alpha = 0.7) +
stat_function(fun = dnorm, args = list(mean = mean(first_semester_grades), sd = sd(first_semester_grades)), color = "red", size = 1) +
labs(title = "First Semester Grades", x = "Grades", y = "Density") +
theme_minimal()
# Plot for second semester
gradeplot2 <- ggplot(data.frame(grade = second_semester_grades), aes(x = grade)) +
geom_histogram(aes(y = ..density..), bins = 10, fill = "#ac1f67", color = "black", alpha = 0.7) +
stat_function(fun = dnorm, args = list(mean = mean(second_semester_grades), sd = sd(second_semester_grades)), color = "blue", size = 1) +
labs(title = "Second Semester Grades", x = "Grades", y = "Density") +
theme_minimal()
# Arrange the two plots side by side
grid.arrange(gradeplot1, gradeplot2, ncol = 2)

Relationship Between
Features
This section examines the relationships between key categorical and
numerical features in the dataset.
Grade Averages
Grade average in the first semester and second semester appear to
have a positive linear relationship. Based on this model, for every
one-unit increase in first semester grade average, we expect to see a
0.7 increase in second-semester grade average.
# Remove rows where Grade1 or Grade2 is zero
filtered_data <- data[data$Grade1 != 0 & data$Grade2 != 0, ]
# Fit a linear regression model
model <- lm(Grade2 ~ Grade1, data = filtered_data)
# Scatterplot of first-semester and second-semester average grades
plot(filtered_data$Grade1, filtered_data$Grade2,
col = "#FFC20A",
pch = 19,
main = "Average Grades",
xlab = "First Semester",
ylab = "Second Semester")
# Add the regression line
abline(model, col = "black", lwd = 2) # Red regression line with thickness of 2

# coefficient of Grade1
slope <- coef(model)[2]
Grades and
Finances
A minority of students have debt or unpaid tuition fees. In the
figure below, the distribution of average grades is stratified by debt
status and also by tuition status. The students in the minority for
these categories appear to have a lower grade distribution. At the 0.05
significance level, there is sufficient evidence to conclude that the
mean average grades differ significantly between these majority and
minority groups. Analytic tasks will include removing or imputating
grade values of zero, then re-examining the relationship.
Distribution of
Average Grades by Debtor Status
col0 = c("#FFC20A", "#0C7BDC")
# Set up layout for the boxplots
par(mfrow = c(1, 2)) # 1 rows, 2 columns
# Create two boxplots
boxplot(data$Grade1 ~ data$Debtor,
col = c("#FFC20A", "#0C7BDC"),
main = "First Semester",
xlab = " ",
ylab = "Average Grade",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles
boxplot(data$Grade2 ~ data$Debtor,
col = c("#FFC20A", "#0C7BDC"),
main = "Second Semester",
xlab = " ",
ylab = " ",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles

Distribution of
Average Grades by Tuition Status
col1 = c("#0C7BDC", "#FFC20A")
# Set up layout for the boxplots
par(mfrow = c(1, 2)) # 1 rows, 2 columns
boxplot(data$Grade1 ~ data$Tuition,
col = col1,
main = "First Semester",
xlab = " ",
ylab = "Average Grade",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles
boxplot(data$Grade2 ~ data$Tuition,
col = col1,
main = "Second Semester",
xlab = " ",
ylab = " ",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles

# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Debtor, data = data))
invisible(t.test(data$Grade2 ~ data$Debtor, data = data))
# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Tuition, data = data))
invisible(t.test(data$Grade2 ~ data$Tuition, data = data))
Grades and
Gender
Male students, accounting for 35.17% of the dataset, appear to
achieve a lower average grade distribution. There is enough evidence to
indicate a significant difference between this group’s mean average
grade and that of female students at the 0.05 significance level.
Analytic tasks will include removing or imputating grade values of zero,
then re-examining the relationship.
Distribution of
Average Grades by Gender
col1 = c("#0C7BDC", "#FFC20A")
# Set up layout for the boxplots
par(mfrow = c(1, 2)) # 1 rows, 2 columns
boxplot(data$Grade1 ~ data$Gender,
col = col1,
main = "First Semester",
xlab = " ",
ylab = "Average Grade",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles
boxplot(data$Grade2 ~ data$Gender,
col = col1,
main = "Second Semester",
xlab = " ",
ylab = " ",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles

# T test between categorical variable and continuous variable
invisible(t.test(data$Grade1 ~ data$Gender, data = data))
invisible(t.test(data$Grade2 ~ data$Gender, data = data))
Curricular Units
This dataset includes multiple variables measuring credits for each
semester: number of curricular units credited, enrolled, and approved. A
significant number of the credited variables for each semester have a
value of zero, more so in the second semester; this may indicate that
the information was recorded before the end of the second semester and
may be incomplete. For this reason, we might consider only including
approved curricular units as a potential variable in our model.
sem1_approved <- data$U_Approved1
sem1_enrolled <- data$U_Enrolled1
sem1_credited <- data$U_Credited1
# Count frequencies of credits for each variable for the first semester
sem1_approved_counts <- as.data.frame(table(sem1_approved))
sem1_enrolled_counts <- as.data.frame(table(sem1_enrolled))
sem1_credited_counts <- as.data.frame(table(sem1_credited))
# Create bar plots for the first semester
plot1 <- ggplot(sem1_approved_counts, aes(x = sem1_approved, y = Freq)) +
geom_bar(stat = "identity", fill = "#ac1f67", color = "black", alpha = 0.7) +
labs(title = " ", x = "Credits Approved", y = "Number of Occurrences") +
theme_minimal() +
theme(axis.text.x = element_blank())
plot2 <- ggplot(sem1_enrolled_counts, aes(x = sem1_enrolled, y = Freq)) +
geom_bar(stat = "identity", fill = "#0C7BDC", color = "black", alpha = 0.7) +
labs(title = "First Semester", x = "Credits Enrolled", y = " ") +
theme_minimal() +
theme(axis.text.x = element_blank())
plot3 <- ggplot(sem1_credited_counts, aes(x = sem1_credited, y = Freq)) +
geom_bar(stat = "identity", fill = "#FFC20A", color = "black", alpha = 0.7) +
labs(title = " ", x = "Credited Units", y = " ") +
theme_minimal() +
theme(axis.text.x = element_blank())
# Arrange the plots side by side for the first semester
grid.arrange(plot1, plot2, plot3, ncol = 3)

sem2_approved <- data$U_Approved2
sem2_enrolled <- data$U_Enrolled2
sem2_credited <- data$U_Credited2
# Count frequencies of credits for each variable for the second semester
sem2_approved_counts <- as.data.frame(table(sem2_approved))
sem2_enrolled_counts <- as.data.frame(table(sem2_enrolled))
sem2_credited_counts <- as.data.frame(table(sem2_credited))
# Create bar plots for the second semester
plot1_2nd <- ggplot(sem2_approved_counts, aes(x = sem2_approved, y = Freq)) +
geom_bar(stat = "identity", fill = "#ac1f67", color = "black", alpha = 0.7) +
labs(title = " ", x = "Credits Approved", y = "Number of Occurrences") +
theme_minimal() +
theme(axis.text.x = element_blank())
plot2_2nd <- ggplot(sem2_enrolled_counts, aes(x = sem2_enrolled, y = Freq)) +
geom_bar(stat = "identity", fill = "#0C7BDC", color = "black", alpha = 0.7) +
labs(title = "Second Semester", x = "Credits Enrolled", y = " ") +
theme_minimal() +
theme(axis.text.x = element_blank())
plot3_2nd <- ggplot(sem2_credited_counts, aes(x = sem2_credited, y = Freq)) +
geom_bar(stat = "identity", fill = "#FFC20A", color = "black", alpha = 0.7) +
labs(title = " ", x = "Credited Units", y = " ") +
theme_minimal() +
theme(axis.text.x = element_blank())
# Arrange the plots side by side for the second semester
grid.arrange(plot1_2nd, plot2_2nd, plot3_2nd, ncol = 3)

Stratifying Grades by
Curricular Unit Group
Based on the boxplots for grades stratified by the curricular unit
approved group, it appears that students with between 4 and 8 curricular
units approved achieve significantly higher grades than those with fewer
than 4 and slightly higher grades on average than those more than 8.
# Create Unit_Group1 based on U_Approved1
data$Unit_Group1 <- cut(data$U_Approved1,
breaks = c(-Inf, 0, 3, 8, Inf),
labels = c("0", "1-3", "4-8", "9+"),
right = TRUE)
# Create Unit_Group2 based on U_Approved2
data$Unit_Group2 <- cut(data$U_Approved2,
breaks = c(-Inf, 0, 3, 8, Inf),
labels = c("0", "1-3", "4-8", "9+"),
right = TRUE)
col2 = c("#FFC20A", "#0C7BDC", "#ac1f67")
# Filter out "0" group from both Unit_Group1 and Unit_Group2
data_filtered1 <- data[data$Unit_Group1 != "0", ]
data_filtered2 <- data[data$Unit_Group2 != "0", ]
# Set up layout for the boxplots
par(mfrow = c(1, 2)) # 1 row, 2 columns
# Create the first boxplot for the first semester, excluding "0" group
boxplot(data_filtered1$Grade1 ~ data_filtered1$Unit_Group1,
col = col2,
main = "First Semester",
xlab = " ",
ylab = "Average Grade",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles
# Create the second boxplot for the second semester, excluding "0" group
boxplot(data_filtered2$Grade2 ~ data_filtered2$Unit_Group2,
col = col2,
main = "Second Semester",
xlab = " ",
ylab = " ",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles

Note a similar trend for the number of evaluations to curricular
units.
# Create Eval_Group1 based on U_Evaluated1
data$Eval_Group1 <- cut(data$U_Evaluated1,
breaks = c(-Inf, 0, 4, 10, Inf),
labels = c("0", "1-4", "5-10", "11+"),
right = TRUE)
# Create Eval_Group2 based on U_Evaluated2
data$Eval_Group2 <- cut(data$U_Evaluated2,
breaks = c(-Inf, 0, 4, 10, Inf),
labels = c("0", "1-4", "5-10", "11+"),
right = TRUE)
col3 = c("#FFC20A", "#0C7BDC", "#ac1f67", "#AFB1F0")
# Set up layout for the boxplots
par(mfrow = c(1, 2)) # 1 row, 2 columns
# Create the first boxplot for the first semester
boxplot(data$Grade1 ~ data$Eval_Group1,
col = col3,
main = "First Semester",
xlab = "Evaluations",
ylab = "Average Grade",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles
# Create the second boxplot for the second semester
boxplot(data$Grade2 ~ data$Eval_Group2,
col = col3,
main = "Second Semester",
xlab = " ",
ylab = " ",
cex.axis = 0.9, # Smaller font size for axis labels
cex.lab = 0.9) # Smaller font size for axis titles

LS0tCnRpdGxlOiAiRXhhbWluaW5nIFJlbGF0aW9uc2hpcHMgQmV0d2VlbiBTb2Npb2Vjb25vbWljIEZhY3RvcnMgYW5kIEFjYWRlbWljIFBlcmZvcm1hbmNlIHRvIEltcHJvdmUgUHJlZGljdGl2ZSBNb2RlbHMgb2YgU3R1ZGVudCBTdWNjZXNzIgphdXRob3I6ICJDaHJpc3RpbmUgS2lsbGlvbiIKZGF0ZTogIlVwZGF0ZWQgRmVicnVhcnkgMTgsIDIwMjUiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jX2NvbGxhcHNlZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICB0aGVtZTogbHVtZW4KICB3b3JkX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGtlZXBfbWQ6IHllcwogIHBkZl9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICBmaWdfd2lkdGg6IDMKICAgIGZpZ19oZWlnaHQ6IDMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogI2FjMWY2NzsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6IHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogc3Ryb25nOwp9Cmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLwogIGZvbnQtc2l6ZTogMTJweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogbm9ybWFsOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7CiAgICBmb250LXdlaWdodDogYm9sZDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6IHNhbnMtc2VyaWY7CiAgICBjb2xvcjogYmxhY2s7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmlmICghcmVxdWlyZSgia25pdHIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCiAgIGxpYnJhcnkoa25pdHIpCn0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKfQppZiAoIXJlcXVpcmUoInBhbG1lcnBlbmd1aW5zIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQp9CmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikKbGlicmFyeShwbG90bHkpCn0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQpsaWJyYXJ5KEdHYWxseSkKfQppZiAoIXJlcXVpcmUoIm5hbmlhciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIm5hbmlhciIpCmxpYnJhcnkobmFuaWFyKQp9CmlmICghcmVxdWlyZSgicG9vbCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInBvb2wiKQpsaWJyYXJ5KHBvb2wpCn0KaWYgKCFyZXF1aXJlKCJEQkkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJEQkkiKQpsaWJyYXJ5KERCSSkKfQppZiAoIXJlcXVpcmUoIlJNeVNRTCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIlJNeVNRTCIpCmxpYnJhcnkoUk15U1FMKQp9CmlmICghcmVxdWlyZSgicmFuZG9tRm9yZXN0IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicmFuZG9tRm9yZXN0IikKbGlicmFyeShyYW5kb21Gb3Jlc3QpCn0KaWYgKCFyZXF1aXJlKCJnZ2lyYXBoIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dpcmFwaCIpCmxpYnJhcnkoZ2dpcmFwaCkKfQppZiAoIXJlcXVpcmUoImhpZ2hjaGFydGVyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQp9CmlmICghcmVxdWlyZSgiYnJvb20iKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbSIpCmxpYnJhcnkoYnJvb20pCn0KaWYgKCFyZXF1aXJlKCJtaWNlIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygibWljZSIpCmxpYnJhcnkobWljZSkKfQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKbGlicmFyeShnZ3Bsb3QyKQp9CmlmICghcmVxdWlyZSgiZHBseXIiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCmxpYnJhcnkoZHBseXIpCn0KaWYgKCFyZXF1aXJlKCJncmlkRXh0cmEiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJncmlkRXh0cmEiKQpsaWJyYXJ5KGdyaWRFeHRyYSkKfQppZiAoIXJlcXVpcmUoInRpZHlyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXIiKQpsaWJyYXJ5KHRpZHlyKQp9CmlmICghcmVxdWlyZSgibWljZSIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIm1pY2UiKQpsaWJyYXJ5KG1pY2UpCn0KCgojIyAKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCmBgYAoKIyAgSW50cm9kdWN0aW9uCgojIyAgVXNpbmcgVGhpcyBEYXRhc2V0IAoKVGhlIHB1cnBvc2Ugb2YgdXNpbmcgdGhpcyBkYXRhIHNldCBpcyB0byBidWlsZCBtb2RlbHMgdGhhdCBwcmVkaWN0IHN0dWRlbnQgYWNhZGVtaWMgc3VjY2Vzcy4gSG93ZXZlciwgYSBzaWduaWZpY2FudCBjaGFsbGVuZ2UgYXNzb2NpYXRlZCB3aXRoIHRoaXMgZW5kZWF2b3IgaXMgdGhlIHN0cm9uZyBjbGFzcyBpbWJhbGFuY2UgaW4gdGhlIGRhdGEsIGFzIGRlc2NyaWJlZCBieSB0aGUgYXV0aG9ycyBpbiAiRWFybHkgUHJlZGljdGlvbiBvZiBzdHVkZW504oCZcyBQZXJmb3JtYW5jZSBpbiBIaWdoZXIgRWR1Y2F0aW9uOiBBIENhc2UgU3R1ZHkuIiBUaGUgZ29hbCBvZiB0aGlzIHJlcG9ydCBpcyB0byB1c2UgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyB0byBleGFtaW5lIHRoZSBmZWF0dXJlcyBjbG9zZWx5IGNvcnJlbGF0ZWQgd2l0aCBzdHVkZW50IGFjYWRlbWljIHBlcmZvcm1hbmNlLCBhcyBtZWFzdXJlZCBieSBmaXJzdC0gYW5kIHNlY29uZC1zZW1lc3RlciBncmFkZSBhdmVyYWdlLiBVbmRlcnN0YW5kaW5nIHRoZXNlIHJlbGF0aW9uc2hpcHMgbWF5IGhlbHAgaW5mb3JtIHRoZSBkZXZlbG9wbWVudCBvZiBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyB0aGF0IG1vcmUgYWNjdXJhdGVseSBwcmVkaWN0IGFjYWRlbWljIHN1Y2Nlc3Mgd2hpbGUgbWl0aWdhdGluZyBiaWFzLiAKCiMjICBEZXNjcmlwdGlvbiBvZiBEYXRhIAoKVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGZlYXR1cmVzIHByb3ZpZGVkIGJ5IGEgaGlnaGVyIGVkdWNhdGlvbiBpbnN0aXR1dGlvbiBpbiBQb3J0dWdhbCBhbmQgY29sbGVjdGVkIGZyb20gdmFyaW91cyBkaXNqb2ludCBkYXRhYmFzZXMgYWJvdXQgc3R1ZGVudHMgYXQgdGhlIHRpbWUgb2YgdGhlaXIgZW5yb2xsbWVudCBpbiBhbiB1bmRlcmdyYWR1YXRlIGRlZ3JlZSBwcm9ncmFtLiBUaGUgcHVycG9zZSBvZiB0aGUgZGF0YXNldCBpcyB0byBwcmVkaWN0IHN0dWRlbnQgZHJvcG91dCBhbmQgYWNhZGVtaWMgc3VjY2Vzcy4gVGhlIGZlYXR1cmVzIHJlbGF0ZSB0byBzdHVkZW50IGRlbW9ncmFwaGljcywgc29jaW8tZWNvbm9taWMgaW5kaWNhdG9ycywgZGVncmVlIHByb2dyYW0sIGFuZCBhY2FkZW1pYyBwZXJmb3JtYW5jZSBhdCB0aGUgZW5kIG9mIHRoZSBmaXJzdCBhbmQgc2Vjb25kIHNlbWVzdGVycy4gVGhlIGNvbGxlY3RlZCBkYXRhIHByZXZpb3VzbHkgdW5kZXJ3ZW50IGNsZWFuaW5nLiAKCiMjICBMaXN0IG9mIEZlYXR1cmVzCgpUaGUgZGF0YXNldCBjb250YWlucyA0LDQyNCBvYnNlcnZhdGlvbnMgYW5kIDM0IGZlYXR1cmUgdmFyaWFibGVzLiAKCi0gKipNYXJpdGFsIFN0YXR1cyoqIChjYXRlZ29yaWNhbCk6IDYgY2F0ZWdvcmllcyBpbmNsdWRlIHNpbmdsZSwgbWFycmllZCwgd2lkb3dlciwgZGl2b3JjZWQsIGRlIGZhY3RvIHVuaW9uLCBvciBsZWdhbGx5IHNlcGFyYXRlZDsgODguNiUgb2Ygc3R1ZGVudHMgYXJlIGNhdGVnb3JpemVkIGFzIHNpbmdsZS4KLSAqKkFwcGxpY2F0aW9uIG1vZGUqKiAoY2F0ZWdvcmljYWwpOiAxOCBjYXRlZ29yaWVzIGluY2x1ZGUgaW5mb3JtYXRpb24gcmVsYXRlZCB0byB0aGUgc3R1ZGVudCdzIGFwcGxpY2F0aW9uIGNsYXNzaWZpZXJzLCBzdWNoIGFzIGludGVybmF0aW9uYWwgc3R1ZGVudCwgc3BlY2lhbCBjb250aW5nZW50LCBzcGVjaWFsIGFnZSBjYXRlZ29yeSwgYW5kIHRyYW5zZmVyIHN0dWRlbnQuCi0gKipBcHBsaWNhdGlvbiBvcmRlcioqIChjYXRlZ29yaWNhbCk6IDggY2F0ZWdvcmllcyBvZiBwcmVmZXJyZWQgYXBwbGljYXRpb24gb3JkZXIgYmV0d2VlbiBmaXJzdCBjaG9pY2UgYW5kIGxhc3QgY2hvaWNlLgotICoqQ291cnNlKiogKGNhdGVnb3JpY2FsKTogMTcgY2F0ZWdvcmllcyBmb3IgY2hvc2VuIGNvdXJzZSBvZiBzdHVkeS4KLSAqKkRheXRpbWUvZXZlbmluZyBhdHRlbmRhbmNlKiogKGJpbmFyeSk6IFdoZXRoZXIgYSBzdHVkZW50IGF0dGVuZHMgZHVyaW5nIHRoZSBkYXkgb3IgaW4gdGhlIGV2ZW5pbmc7IDg5LjA4JSBhdHRlbmQgZHVyaW5nIHRoZSBkYXkuIAotICoqUHJldmlvdXMgUXVhbGlmaWNhdGlvbioqIChjYXRlZ29yaWNhbCk6IDE3IGNhdGVnb3JpZXMgb2YgaGlnaGVzdCBlZHVjYXRpb24gbGV2ZWwsIGZyb20gc2Vjb25kYXJ5IGVkdWNhdGlvbiB0byBtYXN0ZXIncyBkZWdyZWU7IDg0LjAyJSBvZiBzdHVkZW50cyBjb21wbGV0ZWQgdGhlaXIgc2Vjb25kYXJ5IGVkdWNhdGlvbiAoMTJ0aCB5ZWFyIG9mIHNjaG9vbGluZyBvciBlcXVpdmFsZW50KS4KLSAqKk5hdGlvbmFsaXR5KiogKGNhdGVnb3JpY2FsKTogMjEgbmF0aW9uYWxpdGllcyByZXByZXNlbnRlZCwgOTcuNSUgUG9ydHVndWVzZSBhbmQgdGhlIHJlbWFpbmluZyBpbnRlcm5hdGlvbmFsIHN0dWRlbnRzLiAKLSAqKk1vdGhlcidzIFF1YWxpZmljYXRpb24qKiBhbmQgKipGYXRoZXIncyBRdWFsaWZpY2F0aW9uKiogKGNhdGVnb3JpY2FsKTogMjkgYW5kIDM0IGNhdGVnb3JpZXMgb2YgaGlnaGVzdCBlZHVjYXRpb24gbGV2ZWwsIHJlc3BlY3RpdmVseS4gCi0gKipNb3RoZXIncyBPY2N1cGF0aW9uKiogYW5kICoqRmF0aGVyJ3MgT2NjdXBhdGlvbioqIChjYXRlZ29yaWNhbCk6IDMyIGFuZCA0NiBjYXRlZ29yaWVzIG9mIG9jY3VwYXRpb24sIHJlc3BlY3RpdmVseS4gCi0gKipEaXNwbGFjZWQqKiAoYmluYXJ5KTogV2hldGhlciBvciBub3QgYSBzdHVkZW50IGlzIGRpc3BsYWNlZDsgNTQuODQlIG9mIHN0dWRlbnRzIGFyZSBkaXNwbGFjZWQuIAotICoqRWR1Y2F0aW9uYWwgc3BlY2lhbCBuZWVkcyoqIChiaW5hcnkpOiAxLjE1JSBvZiBzdHVkZW50cyByZXBvcnRlZCBlZHVjYXRpb25hbCBzcGVjaWFsIG5lZWRzLgotICoqRGVidG9yKiogKGJpbmFyeSk6IFdoZXRoZXIgb3Igbm90IGEgc3R1ZGVudCBoYXMgZGVidDsgMTEuMzclIG9mIHN0dWRlbnRzIGhhdmUgZGVidC4KLSAqKlR1aXRpb24gZmVlcyB1cCB0byBkYXRlKiogKGJpbmFyeSk6IFdoZXRoZXIgb3Igbm90IGEgc3R1ZGVudCdzIHR1aXRpb24gZmVlcyBhcmUgdXAgdG8gZGF0ZTsgMTEuOTMlIGFyZSBub3QgdXAtdG8tZGF0ZSBvbiB0aGVpciBwYXltZW50cy4gCi0gKipHZW5kZXIqKiAoYmluYXJ5KTogNjQuODMlIG9mIHN0dWRlbnRzIGFyZSBmZW1hbGUgCi0gKipTY2hvbGFyc2hpcCBob2xkZXIqKiAoYmluYXJ5KTogMjQuODQlIG9mIHN0dWRlbnRzIGhvbGQgYSBzY2hvbGFyc2hpcC4gCi0gKipBZ2UgYXQgZW5yb2xsbWVudCoqIChpbnRlZ2VyKTogQWdlIG9mIHRoZSBzdHVkZW50IHdoZW4gdGhleSBhcmUgZW5yb2xsZWQ7IDY0Ljk0JSBhcmUgMjEgeWVhcnMgb2xkIG9yIHlvdW5nZXIuIAotICoqSW50ZXJuYXRpb25hbCBzdHVkZW50KiogKGJpbmFyeSk6IEludGVybmF0aW9uYWwgc3R1ZGVudHMgKGkuZS4sIG5vdCBmcm9tIFBvcnR1Z2FsKSBhY2NvdW50IGZvciAyLjQ5JSBvZiB0aGUgc2FtcGxlLiAKLSAqKkN1cnJpY3VsYXIgVW5pdHMgMXN0IFNlbWVzdGVyKiogYW5kICoqQ3VycmljdWxhciBVbml0cyAybmQgU2VtZXN0ZXIqKiAoaW50ZWdlcnMpOiBOdW1iZXIgb2YgY3VycmljdWxhciB1bml0cyAqKkNyZWRpdGVkKiosICoqRW5yb2xsZWQqKiwgYW5kICoqQXBwcm92ZWQqKiBmb3IgZWFjaCBzZW1lc3Rlci4gKipFdmFsdWF0aW9ucyoqIGVuY29tcGFzc2VzIHRoZSBudW1iZXIgb2YgZXZhbHVhdGlvbnMgdG8gY3VycmljdWxhciB1bml0cyBpbiBlYWNoIHNlbWVzdGVyLCBhbmQgKipXaXRob3V0IEV2YWx1YXRpb25zKiogaXMgdGhlIG51bWJlciBvZiBjdXJyaWN1bGFyIHVuaXRzIHdpdGhvdXQgZXZhbHVhdGlvbnMgaW4gZWFjaCBzZW1lc3Rlci4gKipHcmFkZSoqIGlzIHRoZSBhdmVyYWdlIGdyYWRlIGJldHdlZW4gMCBhbmQgMjAgcGVyIHNlbWVzdGVyLgotIEVjb25vbWljIHZhcmlhYmxlcyAoY29udGludW91cyk6IFRoaXMgZGF0YXNldCBpbmNsdWRlcyBjb250aW51b3VzIHZhcmlhYmxlcyByZWxhdGVkIHRvIHRoZSAqKlVuZW1wbG95bWVudCBSYXRlKiosICoqSW5mbGF0aW9uIFJhdGUqKiwgYW5kICoqR0RQKiouCi0gKipUYXJnZXQqKiAoY2F0ZWdvcmljYWwpOiBBIHN0dWRlbnQncyBhY2FkZW1pYyBvdXRjb21lOiBEcm9wb3V0LCBncmFkdWF0ZSwgZW5yb2xsZWQuIAoKYGBge3IgZGF0YX0KZGF0YSA8LSByZWFkLmNzdigiaHR0cHM6Ly9jaHJpc3RpbmVraWxsaW9uLmdpdGh1Yi5pby9tYWNoaW5lX2xlYXJuaW5nL2RhdGEvc3R1ZGVudC1zdWNjZXNzLmNzdiIpCgojIENoYW5nZSBjb2x1bW4gbmFtZXMKY29sbmFtZXMoZGF0YSkgPC0gYygKICAiTWFyaXRhbCIsICJBcHBsaWNhdGlvbl9NIiwgIkFwcGxpY2F0aW9uX08iLCAiQ291cnNlIiwgCiAgIkF0dGVuZGFuY2UiLCAiU19RdWFsIiwgIk5hdGlvbmFsaXR5IiwgCiAgIk1fUXVhbCIsICJGX1F1YWwiLCAiTV9PY2MiLCAKICAiRl9PY2MiLCAiRGlzcGxhY2VkIiwgIlNwZWNpYWxfTmVlZHMiLCAiRGVidG9yIiwgCiAgIlR1aXRpb24iLCAiR2VuZGVyIiwgIlNjaG9sYXJzaGlwIiwgIkFnZSIsIAogICJJbnRlcm5hdGlvbmFsIiwgIlVfQ3JlZGl0ZWQxIiwgIlVfRW5yb2xsZWQxIiwKICAiVV9FdmFsdWF0ZWQxIiwgIlVfQXBwcm92ZWQxIiwgCiAgIkdyYWRlMSIsICJVX1dPX0V2YWwxIiwgCiAgIlVfQ3JlZGl0ZWQyIiwgIlVfRW5yb2xsZWQyIiwgCiAgIlVfRXZhbHVhdGVkMiIsICJVX0FwcHJvdmVkMiIsIAogICJHcmFkZTIiLCAiVV9XT19FdmFsMiIsIAogICJVbmVtcGxveW1lbnQiLCAiSW5mbGF0aW9uIiwgIkdEUCIsICJUYXJnZXQiCikKCiMgQ3JlYXRlIHJhbmRvbSBvYnNlcnZhdGlvbiBJRCBhbmQgcmVwbGFjZSA4JSBvZiB0aGUgY29ycmVzcG9uZGluZyBvYnNlcnZhdGlvbnMgd2l0aCBtaXNzaW5nIHZhbHVlcyAKZ3JhZGVzMS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjQ0MjQsIDM1MywgcmVwbGFjZSA9IEZBTFNFKQpncmFkZXMyLm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6NDQyNCwgMzU0LCByZXBsYWNlID0gRkFMU0UpIApkYXRhJEdyYWRlMVtncmFkZXMxLm1pc3NpbmcuaWRdIDwtIE5BCmRhdGEkR3JhZGUyW2dyYWRlczIubWlzc2luZy5pZF0gPC0gTkEKCiNUb3RhbCB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW4uCm1pc3NpbmdfcGVyX2NvbHVtbiA8LSBjb2xTdW1zKGlzLm5hKGRhdGEpKQoKI1RvdGFsIHRoZSBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQuIAp0b3RhbF9taXNzaW5nIDwtIHN1bShpcy5uYShkYXRhKSkKYGBgCgojICBEaXN0cmlidXRpb24gb2YgSW5kaXZpZHVhbCBGZWF0dXJlcyAKClRoaXMgc2VjdGlvbiB3aWxsIGRlc2NyaWJlIHRoZSB1bml2YXJpYXRlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIGtleSBjYXRlZ29yaWNhbCwgZGljaG90b21vdXMsIGFuZCBjb250aW51b3VzIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0IGFuZCBhbmFseXplIGFueSBwb3RlbnRpYWwgaXNzdWVzIGZvciBtYWNoaW5lIGxlYXJuaW5nIGFwcGxpY2F0aW9ucy4gCgojIyBTdHVkZW50IEdyb3VwcyBvZiBJbnRlcmVzdCAKClRoZXJlIGFyZSB0aHJlZSBrZXkgZ3JvdXBzIHRoYXQgYXJlIHVuZGVycmVwcmVzZW50ZWQgd2l0aGluIHRoaXMgZGF0YXNldCBhbmQgc2hvdWxkIGJlIGNhcmVmdWxseSBjb25zaWRlcmVkIGluIHRoZSBkZXZlbG9wbWVudCBvZiBtYWNoaW5lIGxlYXJuaW5nIG1vZGVscyBzbyBhcyBub3QgdG8gcmVwcm9kdWNlIGJpYXMuIFNlY3Rpb24gMyBvZiB0aGlzIHJlcG9ydCBleHBsb3JlcyBpbiBtb3JlIGRldGFpbCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlc2UgZ3JvdXBzIGFuZCBhY2FkZW1pYyBhY2hpZXZlbWVudCBpbiB0aGUgZGF0YXNldC4gCgpgYGB7cn0KIyBDb3VudCB0aGUgbnVtYmVyIG9mIG9jY3VycmVuY2VzIGZvciBlYWNoIGNhdGVnb3J5CmRlYnRvcl9jb3VudHMgPC0gdGFibGUoZGF0YSREZWJ0b3IpCnR1aXRpb25fY291bnRzIDwtIHRhYmxlKGRhdGEkVHVpdGlvbikKZ2VuZGVyX2NvdW50cyA8LSB0YWJsZShkYXRhJEdlbmRlcikKCiMgQ3JlYXRlIGRhdGEgZnJhbWVzIGZyb20gdGhlIGNvdW50cyBmb3IgZWFjaCBjYXRlZ29yeQpkZWJ0b3JfZGYgPC0gYXMuZGF0YS5mcmFtZShkZWJ0b3JfY291bnRzKQp0dWl0aW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUodHVpdGlvbl9jb3VudHMpCmdlbmRlcl9kZiA8LSBhcy5kYXRhLmZyYW1lKGdlbmRlcl9jb3VudHMpCgojIFJlY29kZSBiaW5hcnkgdmFsdWVzIGZyb20gbnVtYmVycyB0byBjYXRlZ29yaWVzIApkZWJ0b3JfZGYkVmFyMSA8LSByZWNvZGUoZGVidG9yX2RmJFZhcjEsIGAxYCA9ICJEZWJ0IiwgYDBgID0gIk5vIERlYnQiKQp0dWl0aW9uX2RmJFZhcjEgPC0gcmVjb2RlKHR1aXRpb25fZGYkVmFyMSwgYDFgID0gIlBhaWQiLCBgMGAgPSAiVW5wYWlkIikKZ2VuZGVyX2RmJFZhcjEgPC0gcmVjb2RlKGdlbmRlcl9kZiRWYXIxLCBgMWAgPSAiTWFsZSIsIGAwYCA9ICJGZW1hbGUiKQoKIyBDcmVhdGUgdGhlIHBpZSBjaGFydHMgd2l0aCBnZ3Bsb3QyCgojIERlYnRvciBQaWUgQ2hhcnQKcGllX2RlYnRvciA8LSBnZ3Bsb3QoZGVidG9yX2RmLCBhZXMoeCA9ICIiLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKyAKICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKyAgIyBDb252ZXJ0IGJhciBjaGFydCB0byBwaWUgY2hhcnQKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNEM1N0I4IiwgIiNBRkIxRjAiKSkgKwogIHRoZW1lX3ZvaWQoKSArICAjIFJlbW92ZSBiYWNrZ3JvdW5kIGFuZCBheGVzCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSBOVUxMKSkgKyAgIyBBZGQgbGVnZW5kIGFuZCByZW1vdmUgdGl0bGUKICBnZ3RpdGxlKCJEZWJ0b3IgU3RhdHVzIikgICMgUmVtb3ZlIGluZGl2aWR1YWwgdGl0bGUKCiMgVHVpdGlvbiBGZWVzIFBpZSBDaGFydApwaWVfdHVpdGlvbiA8LSBnZ3Bsb3QodHVpdGlvbl9kZiwgYWVzKHggPSAiIiwgeSA9IEZyZXEsIGZpbGwgPSBWYXIxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsgCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsgICMgQ29udmVydCBiYXIgY2hhcnQgdG8gcGllIGNoYXJ0CiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y1QTFCNSIsICIjYWMxZjY3IikpICsKICB0aGVtZV92b2lkKCkgKyAgIyBSZW1vdmUgYmFja2dyb3VuZCBhbmQgYXhlcwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gTlVMTCkpICsgICMgQWRkIGxlZ2VuZCBhbmQgcmVtb3ZlIHRpdGxlCiAgZ2d0aXRsZSgiVHVpdGlvbiBGZWVzIikgICMgUmVtb3ZlIGluZGl2aWR1YWwgdGl0bGUKCiMgR2VuZGVyIFBpZSBDaGFydApwaWVfZ2VuZGVyIDwtIGdncGxvdChnZW5kZXJfZGYsIGFlcyh4ID0gIiIsIHkgPSBGcmVxLCBmaWxsID0gVmFyMSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArIAogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArICAjIENvbnZlcnQgYmFyIGNoYXJ0IHRvIHBpZSBjaGFydAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNFNkRFM0MiLCAiI0I5QTUyMCIpKSArCiAgdGhlbWVfdm9pZCgpICsgICMgUmVtb3ZlIGJhY2tncm91bmQgYW5kIGF4ZXMKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwpKSArICAjIEFkZCBsZWdlbmQgYW5kIHJlbW92ZSB0aXRsZQogIGdndGl0bGUoIkdlbmRlciIpICAKCiMgQ29tYmluZSB0aGUgcGllIGNoYXJ0cyBpbnRvIGEgZ3JpZCB3aXRoIGEgY2VudGVyZWQgbWFpbiB0aXRsZQpncmlkLmFycmFuZ2UoCiAgcGllX2RlYnRvciwgcGllX3R1aXRpb24sIHBpZV9nZW5kZXIsIAogIG5jb2wgPSAzLCAKICBoZWlnaHRzID0gdW5pdChjKDEsIDAuMSksICJucGMiKSAgIyBBbGxvY2F0ZSBzcGFjZSBmb3IgdGhlIGxlZ2VuZHMKKQpgYGAKCiMjIFBhcmVudGFsIEVkdWNhdGlvbgoKVGhpcyBkYXRhc2V0IGNvbnRhaW5zIHRoZSBwcmV2aW91cyBhY2FkZW1pYyBxdWFsaWZpY2F0aW9ucyBvZiB0aGUgc3R1ZGVudCwgbW90aGVyLCBhbmQgZmF0aGVyLiBGb3Igc3R1ZGVudHMsIDg0LjAyJSBoYXZlIGNvbXBsZXRlZCBzZWNvbmRhcnkgZWR1Y2F0aW9uLiBUaGUgcGFyZW50YWwgcXVhbGlmaWNhdGlvbiBkaXN0cmlidXRpb25zIGRvIG5vdCByZWZsZWN0IHRoYXQgb2YgdGhlIHN0dWRlbnRzOiBUaGVyZSBpcyBhIHdpZGVyIHJhbmdlIG9mIGVkdWNhdGlvbmFsIGNhdGVnb3JpZXMgZm9yIGVhY2ggb2YgdGhlIHBhcmVudCBncm91cHMgKGxpa2VseSBkdWUgdG8gdGhlIGRpc3BhcmF0ZSBzb3VyY2VzIG9mIGRhdGEpLiBXaGVuIHJlY29kZWQgYW5kIGdyb3VwZWQgaW50byB0aHJlZSBtYWluIGNhdGVnb3JpZXMgKHNlY29uZGFyeSBlZHVjYXRpb24sIGhpZ2hlciBlZHVjYXRpb24sIGFuZCBvdGhlciksIHRoZSBkaXN0cmlidXRpb24gb2YgcGFyZW50IHF1YWxpZmljYXRpb25zIGluIHRoZSBkYXRhc2V0IGluZGljYXRlcyB0aGF0IG1vc3Qgb2YgdGhlIHBhcmVudCBxdWFsaWZpY2F0aW9ucyBmYWxsIGludG8gdGhlICJvdGhlciIgY2F0ZWdvcnkuIE1vcmUgcmVjb2RpbmcgaXMgcmVxdWlyZWQgdG8gY2xhc3NpZnkgcXVhbGlmaWNhdGlvbnMgaW4gb3JkZXIgdG8gZXhhbWluZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcGFyZW50IHF1YWxpZmljYXRpb24gYW5kIHN0dWRlbnQgZ3JhZGVzLiAKCmBgYHtyIHF1YWxpZmljYXRpb25zfQojIENyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIDQgcm93cyBhbmQgMzQgY29sdW1ucy4gRmlyc3QgY29sdW1uIGlzIFZhcjEsIDE6MzQKcXVhbCA8LSBkYXRhLmZyYW1lKG1hdHJpeCgxOjM0LCBucm93ID0gMzQsIG5jb2wgPSAxKSkKY29sbmFtZXMocXVhbCkgPC0gYygiVmFyMSIpCgojIENhbGN1bGF0ZSB0aGUgY291bnQgb2YgZWFjaCBjYXRlZ29yeQpTX3F1YWwgPC0gZGF0YS5mcmFtZSh0YWJsZShkYXRhJFNfUXVhbCkpCk1fcXVhbCA8LSBkYXRhLmZyYW1lKHRhYmxlKGRhdGEkTV9RdWFsKSkKRl9xdWFsIDwtIGRhdGEuZnJhbWUodGFibGUoZGF0YSRGX1F1YWwpKQoKIyBNZXJnZSBieSB0aGUgY29tbW9uIGNvbHVtbiAiVmFyMSIKcXVhbCA8LSBtZXJnZShxdWFsLCBTX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKcXVhbCA8LSBtZXJnZShxdWFsLCBNX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKcXVhbCA8LSBtZXJnZShxdWFsLCBGX3F1YWwsIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKCmNvbG5hbWVzKHF1YWwpIDwtIGMoIlF1YWxpZmljYXRpb24iLCAiU3R1ZGVudCIsICJNb3RoZXIiLCAiRmF0aGVyIikKCiMgUmVwbGFjZSBOQXMgd2l0aCAwCnF1YWxbaXMubmEocXVhbCldIDwtIDAKYGBgCgpgYGB7ciBxdWFsaWZpY2F0aW9uc19wYXJlbnRzfQoKIyBQaXZvdCB0aGUgZGF0YSB0byBsb25nIGZvcm1hdApxdWFsX2xvbmcgPC0gcXVhbCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoU3R1ZGVudCwgTW90aGVyLCBGYXRoZXIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiUm9sZSIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiQ291bnQiKQoKIyBGaWx0ZXIgZm9yIG9ubHkgTW90aGVyIGFuZCBGYXRoZXIgcm9sZXMKcXVhbF9sb25nIDwtIHF1YWxfbG9uZyAlPiUKICBmaWx0ZXIoUm9sZSAlaW4lIGMoIk1vdGhlciIsICJGYXRoZXIiKSkKCiMgR3JvdXAgYW5kIHJlbmFtZSB0aGUgJ1F1YWxpZmljYXRpb24nIGNhdGVnb3JpZXMKcXVhbF9sb25nIDwtIHF1YWxfbG9uZyAlPiUKICBtdXRhdGUoUXVhbGlmaWNhdGlvbiA9IGNhc2Vfd2hlbigKICAgIFF1YWxpZmljYXRpb24gPT0gMSB+ICJTZWNvbmRhcnkgRWR1Y2F0aW9uIiwKICAgIFF1YWxpZmljYXRpb24gPj0gMiAmIFF1YWxpZmljYXRpb24gPD0gNiB+ICJIaWdoZXIgRWR1Y2F0aW9uIERlZ3JlZSIsCiAgICBRdWFsaWZpY2F0aW9uID49IDcgJiBRdWFsaWZpY2F0aW9uIDw9IDM0IH4gIk90aGVyIiwKICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoUXVhbGlmaWNhdGlvbikgICMgSW4gY2FzZSB0aGVyZSBhcmUgYW55IE5BIG9yIHVucmVjb2duaXplZCB2YWx1ZXMKICApKQoKIyBBZ2dyZWdhdGUgdGhlIGRhdGEgYnkgUXVhbGlmaWNhdGlvbiBhbmQgUm9sZSB0byBnZXQgdG90YWwgY291bnQKcXVhbF9sb25nX2FnZ3JlZ2F0ZWQgPC0gcXVhbF9sb25nICU+JQogIGdyb3VwX2J5KFF1YWxpZmljYXRpb24sIFJvbGUpICU+JQogIHN1bW1hcmlzZShUb3RhbENvdW50ID0gc3VtKENvdW50KSwgLmdyb3VwcyA9ICdkcm9wJykKCiMgQ3JlYXRlIHRoZSBnZ3Bsb3Qgb2JqZWN0IGZvciBzdGFja2VkIGJhciBwbG90CnAgPC0gZ2dwbG90KHF1YWxfbG9uZ19hZ2dyZWdhdGVkLCBhZXMoeCA9IFF1YWxpZmljYXRpb24sIHkgPSBUb3RhbENvdW50LCBmaWxsID0gUm9sZSwgdGV4dCA9IHBhc3RlKCJUb3RhbCBDb3VudDogIiwgVG90YWxDb3VudCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgICMgVXNlIHN0YXQ9ImlkZW50aXR5IiB0byB1c2UgdGhlIGFjdHVhbCBjb3VudHMKICBsYWJzKHggPSAiUXVhbGlmaWNhdGlvbiIsIHkgPSAiQ291bnQiLCBmaWxsID0gIlJvbGUiKSArCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIFBhcmVudCBRdWFsaWZpY2F0aW9ucyAoR3JvdXBlZCBieSBFZHVjYXRpb24gTGV2ZWwpIikgKyAgIyBBZGQgdGl0bGUgaGVyZQpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJNb3RoZXIiID0gIiNGRkMyMEEiLCAiRmF0aGVyIiA9ICIjMEM3QkRDIikpICsgICMgU2V0IGN1c3RvbSBjb2xvcnMKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIENvbnZlcnQgdGhlIGdncGxvdCBvYmplY3QgdG8gYSBwbG90bHkgb2JqZWN0IGZvciBpbnRlcmFjdGl2aXR5CmludGVyYWN0aXZlX3Bsb3QgPC0gZ2dwbG90bHkocCwgdG9vbHRpcCA9ICJ0ZXh0IikKCiMgU2hvdyB0aGUgaW50ZXJhY3RpdmUgcGxvdAppbnRlcmFjdGl2ZV9wbG90CmBgYAoKCiMjICBHcmFkZSBEaXN0cmlidXRpb24gCgpUaGUgZ3JhZGUgZmVhdHVyZXMgZm9yIGVhY2ggc2VtZXN0ZXIgY29udGFpbiBib3RoIG1pc3NpbmcgdmFsdWVzIGFuZCB2YWx1ZXMgb2YgemVyby4gV2hlbiBncmFkZXMgb2YgemVybyBhcmUgZXhjbHVkZWQsIHRoZSBncmFkZSBkaXN0cmlidXRpb25zIGFyZSBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBEYXRhIGltcHV0YXRpb24gY291bGQgcmVwbGFjZSB0aGUgbWlzc2luZyB2YWx1ZXMsIG9yIGFub3RoZXIgYmluYXJ5IGZlYXR1cmUgY2FuIGJlIGNyZWF0ZWQgdG8gcmV0YWluIHRoZSBpbmZvcm1hdGlvbiBvZiBzdHVkZW50cyB3aXRoIGEgZ3JhZGUgb2YgemVybyBmb3IgZWFjaCBzZW1lc3Rlci4KCmBgYHtyIGdyYWRlLWhpc3RvZ3JhbXN9CgojIFJlbW92ZSBncmFkZXMgb2YgemVybwpmaXJzdF9zZW1lc3Rlcl9ncmFkZXMgPC0gZGF0YSRHcmFkZTFbZGF0YSRHcmFkZTEgIT0gMF0Kc2Vjb25kX3NlbWVzdGVyX2dyYWRlcyA8LSBkYXRhJEdyYWRlMltkYXRhJEdyYWRlMiAhPSAwXQoKIyBQbG90IGZvciBmaXJzdCBzZW1lc3RlcgpncmFkZXBsb3QxIDwtIGdncGxvdChkYXRhLmZyYW1lKGdyYWRlID0gZmlyc3Rfc2VtZXN0ZXJfZ3JhZGVzKSwgYWVzKHggPSBncmFkZSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYmlucyA9IDEwLCBmaWxsID0gIiNhYzFmNjciLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgYXJncyA9IGxpc3QobWVhbiA9IG1lYW4oZmlyc3Rfc2VtZXN0ZXJfZ3JhZGVzKSwgc2QgPSBzZChmaXJzdF9zZW1lc3Rlcl9ncmFkZXMpKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIkZpcnN0IFNlbWVzdGVyIEdyYWRlcyIsIHggPSAiR3JhZGVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBQbG90IGZvciBzZWNvbmQgc2VtZXN0ZXIKZ3JhZGVwbG90MiA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShncmFkZSA9IHNlY29uZF9zZW1lc3Rlcl9ncmFkZXMpLCBhZXMoeCA9IGdyYWRlKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBiaW5zID0gMTAsIGZpbGwgPSAiI2FjMWY2NyIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjcpICsKICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGRub3JtLCBhcmdzID0gbGlzdChtZWFuID0gbWVhbihzZWNvbmRfc2VtZXN0ZXJfZ3JhZGVzKSwgc2QgPSBzZChzZWNvbmRfc2VtZXN0ZXJfZ3JhZGVzKSksIGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiU2Vjb25kIFNlbWVzdGVyIEdyYWRlcyIsIHggPSAiR3JhZGVzIiwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBBcnJhbmdlIHRoZSB0d28gcGxvdHMgc2lkZSBieSBzaWRlCmdyaWQuYXJyYW5nZShncmFkZXBsb3QxLCBncmFkZXBsb3QyLCBuY29sID0gMikKYGBgCgojICBSZWxhdGlvbnNoaXAgQmV0d2VlbiBGZWF0dXJlcwoKVGhpcyBzZWN0aW9uIGV4YW1pbmVzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4ga2V5IGNhdGVnb3JpY2FsIGFuZCBudW1lcmljYWwgZmVhdHVyZXMgaW4gdGhlIGRhdGFzZXQuIAoKIyMgR3JhZGUgQXZlcmFnZXMgCgpHcmFkZSBhdmVyYWdlIGluIHRoZSBmaXJzdCBzZW1lc3RlciBhbmQgc2Vjb25kIHNlbWVzdGVyIGFwcGVhciB0byBoYXZlIGEgcG9zaXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcC4gQmFzZWQgb24gdGhpcyBtb2RlbCwgZm9yIGV2ZXJ5IG9uZS11bml0IGluY3JlYXNlIGluIGZpcnN0IHNlbWVzdGVyIGdyYWRlIGF2ZXJhZ2UsIHdlIGV4cGVjdCB0byBzZWUgYSAwLjcgaW5jcmVhc2UgaW4gc2Vjb25kLXNlbWVzdGVyIGdyYWRlIGF2ZXJhZ2UuIAoKYGBge3IgZ3JhZGVzfQojIFJlbW92ZSByb3dzIHdoZXJlIEdyYWRlMSBvciBHcmFkZTIgaXMgemVybwpmaWx0ZXJlZF9kYXRhIDwtIGRhdGFbZGF0YSRHcmFkZTEgIT0gMCAmIGRhdGEkR3JhZGUyICE9IDAsIF0KCiMgRml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwKbW9kZWwgPC0gbG0oR3JhZGUyIH4gR3JhZGUxLCBkYXRhID0gZmlsdGVyZWRfZGF0YSkKCiMgU2NhdHRlcnBsb3Qgb2YgZmlyc3Qtc2VtZXN0ZXIgYW5kIHNlY29uZC1zZW1lc3RlciBhdmVyYWdlIGdyYWRlcwpwbG90KGZpbHRlcmVkX2RhdGEkR3JhZGUxLCBmaWx0ZXJlZF9kYXRhJEdyYWRlMiwKICAgICBjb2wgPSAiI0ZGQzIwQSIsCiAgICAgcGNoID0gMTksIAogICAgIG1haW4gPSAiQXZlcmFnZSBHcmFkZXMiLAogICAgIHhsYWIgPSAiRmlyc3QgU2VtZXN0ZXIiLAogICAgIHlsYWIgPSAiU2Vjb25kIFNlbWVzdGVyIikKCiMgQWRkIHRoZSByZWdyZXNzaW9uIGxpbmUKYWJsaW5lKG1vZGVsLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAyKSAgIyBSZWQgcmVncmVzc2lvbiBsaW5lIHdpdGggdGhpY2tuZXNzIG9mIDIKCiMgY29lZmZpY2llbnQgb2YgR3JhZGUxCnNsb3BlIDwtIGNvZWYobW9kZWwpWzJdCmBgYAoKIyMgIEdyYWRlcyBhbmQgRmluYW5jZXMKCkEgbWlub3JpdHkgb2Ygc3R1ZGVudHMgaGF2ZSBkZWJ0IG9yIHVucGFpZCB0dWl0aW9uIGZlZXMuIEluIHRoZSBmaWd1cmUgYmVsb3csIHRoZSBkaXN0cmlidXRpb24gb2YgYXZlcmFnZSBncmFkZXMgaXMgc3RyYXRpZmllZCBieSBkZWJ0IHN0YXR1cyBhbmQgYWxzbyBieSB0dWl0aW9uIHN0YXR1cy4gVGhlIHN0dWRlbnRzIGluIHRoZSBtaW5vcml0eSBmb3IgdGhlc2UgY2F0ZWdvcmllcyBhcHBlYXIgdG8gaGF2ZSBhIGxvd2VyIGdyYWRlIGRpc3RyaWJ1dGlvbi4gQXQgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIGxldmVsLCB0aGVyZSBpcyBzdWZmaWNpZW50IGV2aWRlbmNlIHRvIGNvbmNsdWRlIHRoYXQgdGhlIG1lYW4gYXZlcmFnZSBncmFkZXMgZGlmZmVyIHNpZ25pZmljYW50bHkgYmV0d2VlbiB0aGVzZSBtYWpvcml0eSBhbmQgbWlub3JpdHkgZ3JvdXBzLiBBbmFseXRpYyB0YXNrcyB3aWxsIGluY2x1ZGUgcmVtb3Zpbmcgb3IgaW1wdXRhdGluZyBncmFkZSB2YWx1ZXMgb2YgemVybywgdGhlbiByZS1leGFtaW5pbmcgdGhlIHJlbGF0aW9uc2hpcC4gCgoKIyMjIyBEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBHcmFkZXMgYnkgRGVidG9yIFN0YXR1cwpgYGB7ciBib3hwbG90ZGVidH0KY29sMCA9IGMoIiNGRkMyMEEiLCAiIzBDN0JEQyIpCgojIFNldCB1cCBsYXlvdXQgZm9yIHRoZSBib3hwbG90cwpwYXIobWZyb3cgPSBjKDEsIDIpKSAgIyAxIHJvd3MsIDIgY29sdW1ucwoKIyBDcmVhdGUgdHdvIGJveHBsb3RzCmJveHBsb3QoZGF0YSRHcmFkZTEgfiBkYXRhJERlYnRvciwgCiAgICAgICAgY29sID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiksCiAgICAgICAgbWFpbiA9ICJGaXJzdCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCgpib3hwbG90KGRhdGEkR3JhZGUyIH4gZGF0YSREZWJ0b3IsCiAgICAgICAgY29sID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiksCiAgICAgICAgbWFpbiA9ICJTZWNvbmQgU2VtZXN0ZXIiLAogICAgICAgIHhsYWIgPSAiICIsCiAgICAgICAgeWxhYiA9ICIgIiwKICAgICAgICBjZXguYXhpcyA9IDAuOSwgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgbGFiZWxzCiAgICAgICAgY2V4LmxhYiA9IDAuOSkgICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIHRpdGxlcwpgYGAKCiMjIyMgRGlzdHJpYnV0aW9uIG9mIEF2ZXJhZ2UgR3JhZGVzIGJ5IFR1aXRpb24gU3RhdHVzCmBgYHtyIGJveHBsb3R0dWl0aW9ufQoKY29sMSA9IGMoIiMwQzdCREMiLCAiI0ZGQzIwQSIpCgojIFNldCB1cCBsYXlvdXQgZm9yIHRoZSBib3hwbG90cwpwYXIobWZyb3cgPSBjKDEsIDIpKSAgIyAxIHJvd3MsIDIgY29sdW1ucwoKYm94cGxvdChkYXRhJEdyYWRlMSB+IGRhdGEkVHVpdGlvbiwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIkZpcnN0IFNlbWVzdGVyIiwKICAgICAgICB4bGFiID0gIiAiLAogICAgICAgIHlsYWIgPSAiQXZlcmFnZSBHcmFkZSIsCiAgICAgICAgY2V4LmF4aXMgPSAwLjksICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIGxhYmVscwogICAgICAgIGNleC5sYWIgPSAwLjkpICAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyB0aXRsZXMKYm94cGxvdChkYXRhJEdyYWRlMiB+IGRhdGEkVHVpdGlvbiwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKYGBge3IgdHRlc3RfRGVidH0KIyBUIHRlc3QgYmV0d2VlbiBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgY29udGludW91cyB2YXJpYWJsZQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUxIH4gZGF0YSREZWJ0b3IsIGRhdGEgPSBkYXRhKSkKaW52aXNpYmxlKHQudGVzdChkYXRhJEdyYWRlMiB+IGRhdGEkRGVidG9yLCBkYXRhID0gZGF0YSkpCmBgYAoKYGBge3IgdHRlc3RfdHVpdGlvbn0KIyBUIHRlc3QgYmV0d2VlbiBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgY29udGludW91cyB2YXJpYWJsZQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUxIH4gZGF0YSRUdWl0aW9uLCBkYXRhID0gZGF0YSkpCmludmlzaWJsZSh0LnRlc3QoZGF0YSRHcmFkZTIgfiBkYXRhJFR1aXRpb24sIGRhdGEgPSBkYXRhKSkKYGBgCgojIyBHcmFkZXMgYW5kIEdlbmRlcgoKTWFsZSBzdHVkZW50cywgYWNjb3VudGluZyBmb3IgMzUuMTclIG9mIHRoZSBkYXRhc2V0LCBhcHBlYXIgdG8gYWNoaWV2ZSBhIGxvd2VyIGF2ZXJhZ2UgZ3JhZGUgZGlzdHJpYnV0aW9uLiBUaGVyZSBpcyBlbm91Z2ggZXZpZGVuY2UgdG8gaW5kaWNhdGUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhpcyBncm91cCdzIG1lYW4gYXZlcmFnZSBncmFkZSBhbmQgdGhhdCBvZiBmZW1hbGUgc3R1ZGVudHMgYXQgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIGxldmVsLiBBbmFseXRpYyB0YXNrcyB3aWxsIGluY2x1ZGUgcmVtb3Zpbmcgb3IgaW1wdXRhdGluZyBncmFkZSB2YWx1ZXMgb2YgemVybywgdGhlbiByZS1leGFtaW5pbmcgdGhlIHJlbGF0aW9uc2hpcC4gCgoKIyMjIyBEaXN0cmlidXRpb24gb2YgQXZlcmFnZSBHcmFkZXMgYnkgR2VuZGVyCmBgYHtyIGJveHBsb3RnZW5kZXJ9Cgpjb2wxID0gYygiIzBDN0JEQyIsICIjRkZDMjBBIikKCiMgU2V0IHVwIGxheW91dCBmb3IgdGhlIGJveHBsb3RzCnBhcihtZnJvdyA9IGMoMSwgMikpICAjIDEgcm93cywgMiBjb2x1bW5zCgpib3hwbG90KGRhdGEkR3JhZGUxIH4gZGF0YSRHZW5kZXIsIAogICAgICAgIGNvbCA9IGNvbDEsCiAgICAgICAgbWFpbiA9ICJGaXJzdCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmJveHBsb3QoZGF0YSRHcmFkZTIgfiBkYXRhJEdlbmRlciwgCiAgICAgICAgY29sID0gY29sMSwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKYGBge3IgdHRlc3RfZ2VuZGVyfQojIFQgdGVzdCBiZXR3ZWVuIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGFuZCBjb250aW51b3VzIHZhcmlhYmxlCmludmlzaWJsZSh0LnRlc3QoZGF0YSRHcmFkZTEgfiBkYXRhJEdlbmRlciwgZGF0YSA9IGRhdGEpKQppbnZpc2libGUodC50ZXN0KGRhdGEkR3JhZGUyIH4gZGF0YSRHZW5kZXIsIGRhdGEgPSBkYXRhKSkKYGBgCgojIyBDdXJyaWN1bGFyIFVuaXRzIAoKVGhpcyBkYXRhc2V0IGluY2x1ZGVzIG11bHRpcGxlIHZhcmlhYmxlcyBtZWFzdXJpbmcgY3JlZGl0cyBmb3IgZWFjaCBzZW1lc3RlcjogbnVtYmVyIG9mIGN1cnJpY3VsYXIgdW5pdHMgY3JlZGl0ZWQsIGVucm9sbGVkLCBhbmQgYXBwcm92ZWQuIEEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHRoZSBjcmVkaXRlZCB2YXJpYWJsZXMgZm9yIGVhY2ggc2VtZXN0ZXIgaGF2ZSBhIHZhbHVlIG9mIHplcm8sIG1vcmUgc28gaW4gdGhlIHNlY29uZCBzZW1lc3RlcjsgdGhpcyBtYXkgaW5kaWNhdGUgdGhhdCB0aGUgaW5mb3JtYXRpb24gd2FzIHJlY29yZGVkIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSBzZWNvbmQgc2VtZXN0ZXIgYW5kIG1heSBiZSBpbmNvbXBsZXRlLiBGb3IgdGhpcyByZWFzb24sIHdlIG1pZ2h0IGNvbnNpZGVyIG9ubHkgaW5jbHVkaW5nIGFwcHJvdmVkIGN1cnJpY3VsYXIgdW5pdHMgYXMgYSBwb3RlbnRpYWwgdmFyaWFibGUgaW4gb3VyIG1vZGVsLiAKCmBgYHtyIGNyZWRpdF9ieV9zZW1lc3RlcjF9CnNlbTFfYXBwcm92ZWQgPC0gZGF0YSRVX0FwcHJvdmVkMQpzZW0xX2Vucm9sbGVkIDwtIGRhdGEkVV9FbnJvbGxlZDEKc2VtMV9jcmVkaXRlZCA8LSBkYXRhJFVfQ3JlZGl0ZWQxCgojIENvdW50IGZyZXF1ZW5jaWVzIG9mIGNyZWRpdHMgZm9yIGVhY2ggdmFyaWFibGUgZm9yIHRoZSBmaXJzdCBzZW1lc3RlcgpzZW0xX2FwcHJvdmVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfYXBwcm92ZWQpKQpzZW0xX2Vucm9sbGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfZW5yb2xsZWQpKQpzZW0xX2NyZWRpdGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTFfY3JlZGl0ZWQpKQoKIyBDcmVhdGUgYmFyIHBsb3RzIGZvciB0aGUgZmlyc3Qgc2VtZXN0ZXIKcGxvdDEgPC0gZ2dwbG90KHNlbTFfYXBwcm92ZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfYXBwcm92ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNhYzFmNjciLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRzIEFwcHJvdmVkIiwgeSA9ICJOdW1iZXIgb2YgT2NjdXJyZW5jZXMiKSArICAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDIgPC0gZ2dwbG90KHNlbTFfZW5yb2xsZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfZW5yb2xsZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiMwQzdCREMiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICJGaXJzdCBTZW1lc3RlciIsIHggPSAiQ3JlZGl0cyBFbnJvbGxlZCIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDMgPC0gZ2dwbG90KHNlbTFfY3JlZGl0ZWRfY291bnRzLCBhZXMoeCA9IHNlbTFfY3JlZGl0ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNGRkMyMEEiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRlZCBVbml0cyIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKIyBBcnJhbmdlIHRoZSBwbG90cyBzaWRlIGJ5IHNpZGUgZm9yIHRoZSBmaXJzdCBzZW1lc3RlcgpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBwbG90MywgbmNvbCA9IDMpCmBgYAoKYGBge3IgY3JlZGl0X2J5X3NlbWVzdGVyMn0Kc2VtMl9hcHByb3ZlZCA8LSBkYXRhJFVfQXBwcm92ZWQyCnNlbTJfZW5yb2xsZWQgPC0gZGF0YSRVX0Vucm9sbGVkMgpzZW0yX2NyZWRpdGVkIDwtIGRhdGEkVV9DcmVkaXRlZDIKCiMgQ291bnQgZnJlcXVlbmNpZXMgb2YgY3JlZGl0cyBmb3IgZWFjaCB2YXJpYWJsZSBmb3IgdGhlIHNlY29uZCBzZW1lc3RlcgpzZW0yX2FwcHJvdmVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfYXBwcm92ZWQpKQpzZW0yX2Vucm9sbGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfZW5yb2xsZWQpKQpzZW0yX2NyZWRpdGVkX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNlbTJfY3JlZGl0ZWQpKQoKIyBDcmVhdGUgYmFyIHBsb3RzIGZvciB0aGUgc2Vjb25kIHNlbWVzdGVyCnBsb3QxXzJuZCA8LSBnZ3Bsb3Qoc2VtMl9hcHByb3ZlZF9jb3VudHMsIGFlcyh4ID0gc2VtMl9hcHByb3ZlZCwgeSA9IEZyZXEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiI2FjMWY2NyIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjcpICsKICBsYWJzKHRpdGxlID0gIiAiLCB4ID0gIkNyZWRpdHMgQXBwcm92ZWQiLCB5ID0gIk51bWJlciBvZiBPY2N1cnJlbmNlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKcGxvdDJfMm5kIDwtIGdncGxvdChzZW0yX2Vucm9sbGVkX2NvdW50cywgYWVzKHggPSBzZW0yX2Vucm9sbGVkLCB5ID0gRnJlcSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjMEM3QkRDIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIGxhYnModGl0bGUgPSAiU2Vjb25kIFNlbWVzdGVyIiwgeCA9ICJDcmVkaXRzIEVucm9sbGVkIiwgeSA9ICIgIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCgpwbG90M18ybmQgPC0gZ2dwbG90KHNlbTJfY3JlZGl0ZWRfY291bnRzLCBhZXMoeCA9IHNlbTJfY3JlZGl0ZWQsIHkgPSBGcmVxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNGRkMyMEEiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICIgIiwgeCA9ICJDcmVkaXRlZCBVbml0cyIsIHkgPSAiICIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKIyBBcnJhbmdlIHRoZSBwbG90cyBzaWRlIGJ5IHNpZGUgZm9yIHRoZSBzZWNvbmQgc2VtZXN0ZXIKZ3JpZC5hcnJhbmdlKHBsb3QxXzJuZCwgcGxvdDJfMm5kLCBwbG90M18ybmQsIG5jb2wgPSAzKQpgYGAKCgojIyBTdHJhdGlmeWluZyBHcmFkZXMgYnkgQ3VycmljdWxhciBVbml0IEdyb3VwCgpCYXNlZCBvbiB0aGUgYm94cGxvdHMgZm9yIGdyYWRlcyBzdHJhdGlmaWVkIGJ5IHRoZSBjdXJyaWN1bGFyIHVuaXQgYXBwcm92ZWQgZ3JvdXAsIGl0IGFwcGVhcnMgdGhhdCBzdHVkZW50cyB3aXRoIGJldHdlZW4gNCBhbmQgOCBjdXJyaWN1bGFyIHVuaXRzIGFwcHJvdmVkIGFjaGlldmUgc2lnbmlmaWNhbnRseSBoaWdoZXIgZ3JhZGVzIHRoYW4gdGhvc2Ugd2l0aCBmZXdlciB0aGFuIDQgYW5kIHNsaWdodGx5IGhpZ2hlciBncmFkZXMgb24gYXZlcmFnZSB0aGFuIHRob3NlIG1vcmUgdGhhbiA4LiAKCgpgYGB7ciBjcmVkaXRzX2FwcHJvdmVkX2dyb3VwZWR9CiMgQ3JlYXRlIFVuaXRfR3JvdXAxIGJhc2VkIG9uIFVfQXBwcm92ZWQxCmRhdGEkVW5pdF9Hcm91cDEgPC0gY3V0KGRhdGEkVV9BcHByb3ZlZDEsIAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIDAsIDMsIDgsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEtMyIsICI0LTgiLCAiOSsiKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKQoKIyBDcmVhdGUgVW5pdF9Hcm91cDIgYmFzZWQgb24gVV9BcHByb3ZlZDIKZGF0YSRVbml0X0dyb3VwMiA8LSBjdXQoZGF0YSRVX0FwcHJvdmVkMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgMCwgMywgOCwgSW5mKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMS0zIiwgIjQtOCIsICI5KyIpLAogICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUpCmBgYAoKYGBge3IgZ3JhZGVfY3JlZGl0c19ib3hwbG90fQpjb2wyID0gYygiI0ZGQzIwQSIsICIjMEM3QkRDIiwgIiNhYzFmNjciKQoKIyBGaWx0ZXIgb3V0ICIwIiBncm91cCBmcm9tIGJvdGggVW5pdF9Hcm91cDEgYW5kIFVuaXRfR3JvdXAyCmRhdGFfZmlsdGVyZWQxIDwtIGRhdGFbZGF0YSRVbml0X0dyb3VwMSAhPSAiMCIsIF0KZGF0YV9maWx0ZXJlZDIgPC0gZGF0YVtkYXRhJFVuaXRfR3JvdXAyICE9ICIwIiwgXQoKIyBTZXQgdXAgbGF5b3V0IGZvciB0aGUgYm94cGxvdHMKcGFyKG1mcm93ID0gYygxLCAyKSkgICMgMSByb3csIDIgY29sdW1ucwoKIyBDcmVhdGUgdGhlIGZpcnN0IGJveHBsb3QgZm9yIHRoZSBmaXJzdCBzZW1lc3RlciwgZXhjbHVkaW5nICIwIiBncm91cApib3hwbG90KGRhdGFfZmlsdGVyZWQxJEdyYWRlMSB+IGRhdGFfZmlsdGVyZWQxJFVuaXRfR3JvdXAxLCAKICAgICAgICBjb2wgPSBjb2wyLAogICAgICAgIG1haW4gPSAiRmlyc3QgU2VtZXN0ZXIiLAogICAgICAgIHhsYWIgPSAiICIsCiAgICAgICAgeWxhYiA9ICJBdmVyYWdlIEdyYWRlIiwKICAgICAgICBjZXguYXhpcyA9IDAuOSwgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgbGFiZWxzCiAgICAgICAgY2V4LmxhYiA9IDAuOSkgICAjIFNtYWxsZXIgZm9udCBzaXplIGZvciBheGlzIHRpdGxlcwoKIyBDcmVhdGUgdGhlIHNlY29uZCBib3hwbG90IGZvciB0aGUgc2Vjb25kIHNlbWVzdGVyLCBleGNsdWRpbmcgIjAiIGdyb3VwCmJveHBsb3QoZGF0YV9maWx0ZXJlZDIkR3JhZGUyIH4gZGF0YV9maWx0ZXJlZDIkVW5pdF9Hcm91cDIsCiAgICAgICAgY29sID0gY29sMiwKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKTm90ZSBhIHNpbWlsYXIgdHJlbmQgZm9yIHRoZSBudW1iZXIgb2YgZXZhbHVhdGlvbnMgdG8gY3VycmljdWxhciB1bml0cy4gCgpgYGB7ciBldmFsX2dyb3VwZWR9CiMgQ3JlYXRlIEV2YWxfR3JvdXAxIGJhc2VkIG9uIFVfRXZhbHVhdGVkMQpkYXRhJEV2YWxfR3JvdXAxIDwtIGN1dChkYXRhJFVfRXZhbHVhdGVkMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgMCwgNCwgMTAsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwIiwgIjEtNCIsICI1LTEwIiwgIjExKyIpLAogICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUpCgojIENyZWF0ZSBFdmFsX0dyb3VwMiBiYXNlZCBvbiBVX0V2YWx1YXRlZDIKZGF0YSRFdmFsX0dyb3VwMiA8LSBjdXQoZGF0YSRVX0V2YWx1YXRlZDIsIAogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIDAsIDQsIDEwLCBJbmYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCIsICIxLTQiLCAiNS0xMCIsICIxMSsiKSwKICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKQpgYGAKCmBgYHtyIGdyYWRlX2V2YWxfYm94cGxvdH0KY29sMyA9IGMoIiNGRkMyMEEiLCAiIzBDN0JEQyIsICIjYWMxZjY3IiwgIiNBRkIxRjAiKQoKIyBTZXQgdXAgbGF5b3V0IGZvciB0aGUgYm94cGxvdHMKcGFyKG1mcm93ID0gYygxLCAyKSkgICMgMSByb3csIDIgY29sdW1ucwoKIyBDcmVhdGUgdGhlIGZpcnN0IGJveHBsb3QgZm9yIHRoZSBmaXJzdCBzZW1lc3Rlcgpib3hwbG90KGRhdGEkR3JhZGUxIH4gZGF0YSRFdmFsX0dyb3VwMSwgCiAgICAgICAgY29sID0gY29sMywKICAgICAgICBtYWluID0gIkZpcnN0IFNlbWVzdGVyIiwKICAgICAgICB4bGFiID0gIkV2YWx1YXRpb25zIiwKICAgICAgICB5bGFiID0gIkF2ZXJhZ2UgR3JhZGUiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCgojIENyZWF0ZSB0aGUgc2Vjb25kIGJveHBsb3QgZm9yIHRoZSBzZWNvbmQgc2VtZXN0ZXIKYm94cGxvdChkYXRhJEdyYWRlMiB+IGRhdGEkRXZhbF9Hcm91cDIsCiAgICAgICAgY29sID0gY29sMywKICAgICAgICBtYWluID0gIlNlY29uZCBTZW1lc3RlciIsCiAgICAgICAgeGxhYiA9ICIgIiwKICAgICAgICB5bGFiID0gIiAiLAogICAgICAgIGNleC5heGlzID0gMC45LCAgIyBTbWFsbGVyIGZvbnQgc2l6ZSBmb3IgYXhpcyBsYWJlbHMKICAgICAgICBjZXgubGFiID0gMC45KSAgICMgU21hbGxlciBmb250IHNpemUgZm9yIGF4aXMgdGl0bGVzCmBgYAoKCiMgIFJlZmVyZW5jZXMgCgoqKkRBVEEqKjogTS5WLk1hcnRpbnMsIEQuIFRvbGxlZG8sIEouIE1hY2hhZG8sIEwuIE0uVC4gQmFwdGlzdGEsIFYuUmVhbGluaG8uICgyMDIxKS4gUHJlZGljdCBTdHVkZW50cycgRHJvcG91dCBhbmQgQWNhZGVtaWMgU3VjY2Vzcy4gS2FnZ2xlLiBBdHRyaWJ1dGlvbiA0LjAgSW50ZXJuYXRpb25hbCAoQ0MgQlkgNC4wKS4gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9oYXJzaGl0c3JpdmFzdGF2YTI1L3ByZWRpY3Qtc3R1ZGVudHMtZHJvcG91dC1hbmQtYWNhZGVtaWMtc3VjY2Vzcy9kYXRhIA==